<?php
// 应用公共文件
use app\common\service\admin\AuthService;
use app\common\service\admin\LibAuthService;
use think\facade\Db;
use think\facade\Route;

if ( ! function_exists('__')) {
    /**
     * 获取语言变量值，同TP lang()方法一致
     *
     * @param string $name
     * @param array  $vars
     * @param string $lang
     *
     * @return mixed
     */
    function __(string $name, array $vars = [], string $lang = '')
    {
        return lang($name, $vars, $lang);
    }
}

if ( ! function_exists('cmf_get_admin_id')) {
    /**
     * 获取后台已登录的管理员id
     * @return mixed|string|unknown|null
     */
    function cmf_get_admin_id()
    {
        return session('admin.id');
    }
}

if ( ! function_exists('cmf_get_admin_username')) {
    /**
     * 获取后台已登录的管理员用户名
     * @return string
     */
    function cmf_get_admin_username()
    {
        return session('admin.username');
    }
}

if ( ! function_exists('cmf_get_admin_role_id')) {
    /**
     * 获取当前登录的管理员角色id
     * @return int
     */
    function cmf_get_admin_role_id()
    {
        $libAuth = new LibAuthService();
        $roleId  = $libAuth->getChildrenGroupIds(true);

        return $roleId;
    }
}

if ( ! function_exists('cmf_get_user_id')) {
    /**
     * 根据手机号获取前台会员id
     */
    function cmf_get_user_id($mobile)
    {
        $userModel = new app\common\model\User();
        $user      = $userModel->where(array('mobile' => $mobile))->find();
        if ($user) {
            return $user->id;
        } else {
            return false;
        }
    }
}

if ( ! function_exists('cmf_get_image_url')) {
    /**
     * 转化数据库保存图片的文件路径，为可以访问的url
     *
     * @param string $file  文件路径，数据存储的文件相对路径
     * @param string $style 图片样式
     *
     * @return string 图片链接
     */
    function cmf_get_image_url($file, $style = '')
    {
        if (empty($file)) {
            return '';
        }

        if (strpos($file, "http") === 0) {
            return $file;
        } else {
            if (strpos($file, "/") === 0) {
                return cmf_get_domain().$file;
            }
        }
    }
}

if ( ! function_exists('check_auth')) {
    /**
     * 按钮权限验证，可判断当前是否有权限操作
     *
     * @param string|array $rule_name 需要验证的规则列表,支持逗号分隔的权限规则或索引数组
     * @param int          $admin_id  可以选择用户id,默认为空：当前已登录用户
     */
    function check_auth($rule_name = '', $admin_id = '')
    {
        $Auth = AuthService::instance();

        if (empty($admin_id)) {
            $admin_id = cmf_get_admin_id();
        }

        return $Auth->check($rule_name, $admin_id);
    }
}

if ( ! function_exists('cmf_get_domain')) {
    /**
     * 返回带协议的域名
     */
    function cmf_get_domain()
    {
        return request()->domain();
    }
}

if ( ! function_exists('cmf_password')) {
    /**
     * CMF密码加密方法
     *
     * @param string $pw       要加密的原始密码
     * @param string $authCode 加密字符串,salt
     *
     * @return string
     */
    function cmf_password($pw, $authCode = 'abc123')
    {
        $result = md5('###'.md5($pw).$authCode);

        return $result;
    }
}

if ( ! function_exists('get_client_ip')) {
    /**
     * 获取客户端IP地址
     *
     * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
     * @param boolean $adv  是否进行高级模式获取（有可能被伪装）
     *
     * @return string
     */
    function get_client_ip($type = 0, $adv = true)
    {
        return request()->ip($type, $adv);
    }
}

if ( ! function_exists('get_config')) {
    /**
     * 获取系统配置信息(config表)
     *
     * @param $key 键值，可为空，为空获取整个数组
     *
     * @return array|string
     */
    function get_config($key = '')
    {
        $cacheData = cache('cacheSystemConfig');
        if ( ! empty($cacheData)) {
            $data = $cacheData;
        } else {
            $data = Db::name('config')->where('status', 1)->select()->toArray();
            cache('cacheSystemConfig', $data);
        }
        $configs = array();
        foreach ($data as $val) {
            $configs[$val['name']] = $val['value'];
        }
        if ( ! $key) {
            return $configs;
        } else {
            return array_key_exists($key, $configs) ? $configs[$key] : '';
        }
    }
}

if ( ! function_exists('xdebug')) {
    /**
     * debug调试
     * 该调试是打印到指定文件夹 public/xdebug/20230225.txt(文件命名取当前年月日)
     *
     * @param string|array $data   打印信息
     * @param string       $type   类型
     * @param string       $suffix 文件后缀名
     * @param bool         $force
     * @param null         $file
     */
    function xdebug($data, $type = 'xdebug', $suffix = null, $force = false, $file = null)
    {
        ! is_dir(public_path().'xdebug/') && mkdir(public_path().'xdebug/');
        if (is_null($file)) {
            $file = is_null($suffix) ? public_path().'xdebug/'.date('Ymd').'.txt' : public_path().'xdebug/'.date('Ymd')."_{$suffix}".'.txt';
        }
        file_put_contents($file,
            "[".date('Y-m-d H:i:s')."] "."========================= {$type} ===========================".PHP_EOL,
            FILE_APPEND);
        $str = (is_string($data) ? $data : (is_array($data) || is_object($data) ? print_r($data,
                true) : var_export($data, true))).PHP_EOL;

        $force ? file_put_contents($file, $str) : file_put_contents($file, $str, FILE_APPEND);
    }
}

/**
 * curl -get请求
 *
 * @param string $url URL to fetch
 */
if ( ! function_exists('curl_get')) {
    function curl_get($url)
    {
        $ch       = curl_init();
        $header[] = "";
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_REFERER, $url);
        curl_setopt($ch, CURLOPT_USERAGENT,
            "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36");
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $content = curl_exec($ch);
        curl_close($ch);

        return $content;
    }
}

/**
 * curl post 请求
 *
 * @param $post_url  请求地址
 * @param $post_data 请求数据
 *
 * @return bool|mixed|string
 */
if ( ! function_exists('curl_post')) {
    function curl_post($post_url, $post_data, $header = [])
    {
        if (is_array($post_data)) {
            $post_data = http_build_query($post_data);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_URL, $post_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
        curl_setopt($ch, CURLOPT_USERAGENT, '');
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $output = curl_exec($ch);
        curl_close($ch);

        return $output;
    }
}

if ( ! function_exists('is_file')) {
    /**
     * 判断内容是否为文件
     *
     * @param $file
     *
     * @return bool
     */
    function is_file($file)
    {
        if (is_file($file) !== false) {
            return true;
        } else {
            return false;
        }
    }

}

if ( ! function_exists('array_format_key')) {
    /**
     * 二位数组重新组合数据
     *
     * @param $array
     * @param $key
     *
     * @return array
     */
    function array_format_key($array, $key)
    {
        $newArray = [];
        foreach ($array as $vo) {
            $newArray[$vo[$key]] = $vo;
        }

        return $newArray;
    }

}

if ( ! function_exists('get_dir')) {
    /**
     * 获取文件目录列表,该方法返回数组
     */
    function get_dir($dir)
    {
        $dirArray[] = null;
        if (false != ($handle = opendir($dir))) {
            $i = 0;
            while (false !== ($file = readdir($handle))) {
                //去掉"“.”、“..”以及带“.xxx”后缀的文件
                if ($file != "." && $file != ".." && ! strpos($file, ".")) {
                    $dirArray[$i] = $file;
                    $i++;
                }
            }
            //关闭句柄
            closedir($handle);
        }

        return $dirArray;
    }
}

if ( ! function_exists('dir_path')) {
    /**
     * 列出目录下所有文件
     *
     * @param string $path 路径
     * @param string $exts 扩展名
     * @param array  $list 增加的文件列表
     *
     * @return  array  所有满足条件的文件
     */
    function dir_path($path)
    {
        $path = str_replace('\\', '/', $path);
        if (substr($path, -1) != '/') {
            $path = $path.'/';
        }

        return $path;
    }
}

if ( ! function_exists('dir_delete')) {
    /**
     * 删除目录及目录下面的所有文件
     *
     * @param string $dir 路径
     *
     * @return  bool   如果成功则返回 TRUE，失败则返回 FALSE
     */
    function dir_delete($dir)
    {
        $dir = dir_path($dir);
        if ( ! is_dir($dir)) {
            return false;
        }
        $list = glob($dir.'*');
        foreach ($list as $v) {
            is_dir($v) ? dir_delete($v) : @unlink($v);
        }

        return @rmdir($dir);
    }
}

if ( ! function_exists('sizecount')) {
    /**
     * 转换字节数为其他单位
     *
     * @param string $filesize 字节大小
     *
     * @return    string    返回大小
     */
    function sizecount($filesize)
    {
        if ($filesize >= 1073741824) {
            $filesize = round($filesize / 1073741824 * 100) / 100 .' GB';
        } elseif ($filesize >= 1048576) {
            $filesize = round($filesize / 1048576 * 100) / 100 .' MB';
        } elseif ($filesize >= 1024) {
            $filesize = round($filesize / 1024 * 100) / 100 .' KB';
        } else {
            $filesize = $filesize.' Bytes';
        }

        return $filesize;
    }
}

if ( ! function_exists('camelize')) {
    /**
     * 下划线转驼峰
     * 思路:
     * step1.原字符串转小写,原字符串中的分隔符用空格替换,在字符串开头加上分隔符
     * step2.将字符串中每个单词的首字母转换为大写,再去空格,去字符串首部附加的分隔符.
     */
    function camelize($uncamelized_words, $separator = '_')
    {
        $uncamelized_words = $separator.str_replace($separator, " ", strtolower($uncamelized_words));

        return ltrim(str_replace(" ", "", ucwords($uncamelized_words)), $separator);
    }
}

if ( ! function_exists('uncamelize')) {
    /**
     * 　　* 驼峰命名转下划线命名
     * 　　* 思路:
     * 　　* 小写和大写紧挨一起的地方,加上分隔符,然后全部转小写
     * 　　*/
    function uncamelize($camelCaps, $separator = '_')
    {
        return strtolower(preg_replace('/([a-z])([A-Z])/', "$1".$separator."$2", $camelCaps));
    }
}

if ( ! function_exists('cmf_parse_name')) {
    /**
     * 字符串命名风格转换
     * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
     *
     * @param string  $name    字符串
     * @param integer $type    转换类型
     * @param bool    $ucfirst 首字母是否大写（驼峰规则）
     *
     * @return string
     */
    function cmf_parse_name($name, $type = 0, $ucfirst = true)
    {
        if ($type) {
            $name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
                return strtoupper($match[1]);
            }, $name);

            return $ucfirst ? ucfirst($name) : lcfirst($name);
        }

        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
    }
}

if ( ! function_exists('cmf_scan_dir')) {
    /**
     * 替代scan_dir的方法
     *
     * @param string $pattern 检索模式 搜索模式 *.txt,*.doc; (同glog方法)
     * @param int    $flags
     * @param        $pattern
     *
     * @return array
     */
    function cmf_scan_dir($pattern, $flags = null)
    {
        $files = glob($pattern, $flags);
        if (empty($files)) {
            $files = [];
        } else {
            $files = array_map('basename', $files);
        }

        return $files;
    }
}

if ( ! function_exists('file_down')) {
    /**
     * 文件下载
     *
     * @param $filepath 文件路径
     * @param $filename 文件名称
     */
    function file_down($filepath, $filename = '')
    {
        if ( ! $filename) {
            $filename = basename($filepath);
        }
        if (is_ie()) {
            $filename = rawurlencode($filename);
        }
        $filetype = file_ext($filename);
        $filesize = sprintf("%u", filesize($filepath));
        if (ob_get_length() !== false) {
            @ob_end_clean();
        }
        header('Pragma: public');
        header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
        header('Cache-Control: no-store, no-cache, must-revalidate');
        header('Cache-Control: pre-check=0, post-check=0, max-age=0');
        header('Content-Transfer-Encoding: binary');
        header('Content-Encoding: none');
        header('Content-type: '.$filetype);
        header('Content-Disposition: attachment; filename="'.$filename.'"');
        header('Content-length: '.$filesize);
        readfile($filepath);
        exit;
    }
}

if ( ! function_exists('is_ie')) {
    /**
     * IE浏览器判断
     */
    function is_ie()
    {
        $useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
        if ((strpos($useragent, 'opera') !== false) || (strpos($useragent, 'konqueror') !== false)) {
            return false;
        }
        if (strpos($useragent, 'msie ') !== false) {
            return true;
        }

        return false;
    }
}

if ( ! function_exists('file_ext')) {
    /**
     * 取得文件扩展
     *
     * @param $filename 文件名
     *
     * @return 扩展名
     */
    function file_ext($filename)
    {
        return strtolower(trim(substr(strrchr($filename, '.'), 1, 10)));
    }
}

if ( ! function_exists('array2level')) {
    /**
     * 数组层级缩进转换
     *
     * @param array $array 源数组
     * @param int   $pid
     * @param int   $level
     *
     * @return array
     */
    function array2level($array, $pid = 0, $level = 1)
    {
        static $list = [];
        foreach ($array as $v) {
            if ($v['pid'] == $pid) {
                $v['level'] = $level;
                $list[]     = $v;
                array2level($array, $v['id'], $level + 1);
            }
        }

        return $list;
    }
}

if ( ! function_exists('str_cut')) {
    /**
     * 字符截取
     *
     * @param $string    要截取的字符串
     * @param $length    截取长度
     * @param $dot       截取之后用什么表示
     * @param $code      编码格式，支持UTF8/GBK
     */
    function str_cut($string, $length, $dot = '...', $code = 'utf-8')
    {
        $strlen = strlen($string);
        if ($strlen <= $length) {
            return $string;
        }
        $string = str_replace(array(
            ' ',
            '&nbsp;',
            '&amp;',
            '&quot;',
            '&#039;',
            '&ldquo;',
            '&rdquo;',
            '&mdash;',
            '&lt;',
            '&gt;',
            '&middot;',
            '&hellip;',
            '\r\n'
        ), array('∵', ' ', '&', '"', "'", '“', '”', '—', '<', '>', '·', '…'), $string);
        $strcut = '';
        if ($code == 'utf-8') {
            $length = intval($length - strlen($dot) - $length / 3);
            $n      = $tn = $noc = 0;
            while ($n < strlen($string)) {
                $t = ord($string[$n]);
                if ($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
                    $tn = 1;
                    $n++;
                    $noc++;
                } elseif (194 <= $t && $t <= 223) {
                    $tn  = 2;
                    $n   += 2;
                    $noc += 2;
                } elseif (224 <= $t && $t <= 239) {
                    $tn  = 3;
                    $n   += 3;
                    $noc += 2;
                } elseif (240 <= $t && $t <= 247) {
                    $tn  = 4;
                    $n   += 4;
                    $noc += 2;
                } elseif (248 <= $t && $t <= 251) {
                    $tn  = 5;
                    $n   += 5;
                    $noc += 2;
                } elseif ($t == 252 || $t == 253) {
                    $tn  = 6;
                    $n   += 6;
                    $noc += 2;
                } else {
                    $n++;
                }
                if ($noc >= $length) {
                    break;
                }
            }
            if ($noc > $length) {
                $n -= $tn;
            }
            $strcut = substr($string, 0, $n);
            $strcut = str_replace(array('∵', '&', '"', "'", '“', '”', '—', '<', '>', '·', '…'), array(
                ' ',
                '&amp;',
                '&quot;',
                '&#039;',
                '&ldquo;',
                '&rdquo;',
                '&mdash;',
                '&lt;',
                '&gt;',
                '&middot;',
                '&hellip;'
            ), $strcut);
        } else {
            $dotlen      = strlen($dot);
            $maxi        = $length - $dotlen - 1;
            $current_str = '';
            $search_arr  = array('&', ' ', '"', "'", '“', '”', '—', '<', '>', '·', '…', '∵');
            $replace_arr = array(
                '&amp;',
                '&nbsp;',
                '&quot;',
                '&#039;',
                '&ldquo;',
                '&rdquo;',
                '&mdash;',
                '&lt;',
                '&gt;',
                '&middot;',
                '&hellip;',
                ' '
            );
            $search_flip = array_flip($search_arr);
            for ($i = 0; $i < $maxi; $i++) {
                $current_str = ord($string[$i]) > 127 ? $string[$i].$string[++$i] : $string[$i];
                if (in_array($current_str, $search_arr)) {
                    $key         = $search_flip[$current_str];
                    $current_str = str_replace($search_arr[$key], $replace_arr[$key], $current_str);
                }
                $strcut .= $current_str;
            }
        }

        return $strcut.$dot;
    }
}

/**
 * 获取客户端操作系统
 * php_uname()
 *
 * @param $agent //$_SERVER['HTTP_USER_AGENT']
 *
 * @return array[os]            操作系统名称
 * @return array[os_ver]        操作系统版本号
 * @return array[equipment]     终端设备类型
 */
function get_client_os($agent = '')
{
    $os        = '';
    $equipment = '';
    $os_ver    = php_uname();
    //window系统
    $agent = strtolower($agent);
    if (stripos($agent, 'window')) {
        $os        = 'Windows';
        $equipment = '电脑';
        if (preg_match('/nt 6.0/i', $agent)) {
            $os_ver = 'Vista';
        } elseif (preg_match('/nt 11.0/i', $agent)) {
            $os_ver = '11';
        } elseif (preg_match('/nt 10.0/i', $agent)) {
            $os_ver = '10';
        } elseif (preg_match('/nt 6.3/i', $agent)) {
            $os_ver = '8.1';
        } elseif (preg_match('/nt 6.2/i', $agent)) {
            $os_ver = '8.0';
        } elseif (preg_match('/nt 6.1/i', $agent)) {
            $os_ver = '7';
        } elseif (preg_match('/nt 5.1/i', $agent)) {
            $os_ver = 'XP';
        } elseif (preg_match('/nt 5/i', $agent)) {
            $os_ver = '2000';
        } elseif (preg_match('/nt 98/i', $agent)) {
            $os_ver = '98';
        } elseif (preg_match('/nt/i', $agent)) {
            $os_ver = 'nt';
        } else {
            $os_ver = '';
        }
        if (preg_match('/x64/i', $agent)) {
            $os .= '(x64)';
        } elseif (preg_match('/x32/i', $agent)) {
            $os .= '(x32)';
        }
    } elseif (stripos($agent, 'linux')) {
        if (stripos($agent, 'android')) {
            preg_match('/android\s([\d\.]+)/i', $agent, $match);
            $os        = 'Android';
            $equipment = 'Mobile phone';
            $os_ver    = $match[1];
        } else {
            $os = 'Linux';
        }
    } elseif (stripos($agent, 'unix')) {
        $os = 'Unix';
    } elseif (preg_match('/iPhone|iPad|iPod/i', $agent)) {
        preg_match('/OS\s([0-9_\.]+)/i', $agent, $match);
        $os     = 'IOS';
        $os_ver = str_replace('_', '.', $match[1]);
        if (preg_match('/iPhone/i', $agent)) {
            $equipment = 'iPhone';
        } elseif (preg_match('/iPad/i', $agent)) {
            $equipment = 'iPad';
        } elseif (preg_match('/iPod/i', $agent)) {
            $equipment = 'iPod';
        }
    } elseif (stripos($agent, 'mac os')) {
        preg_match('/Mac OS X\s([0-9_\.]+)/i', $agent, $match);
        $os        = 'Mac OS X';
        $equipment = '电脑';
        $os_ver    = str_replace('_', '.', $match[1]);
    } else {
        $os = 'Other';
    }

    return ['os' => $os, 'os_ver' => $os_ver, 'equipment' => $equipment];
}

if ( ! function_exists('get_client_browser')) {
    /**
     * 获取客户端浏览器以及版本号
     *
     * @param $agent //$_SERVER['HTTP_USER_AGENT']
     *
     * @return array[browser]       浏览器名称
     * @return array[browser_ver]   浏览器版本号
     */
    function get_client_browser($agent = '')
    {
        $browser     = '';
        $browser_ver = '';
        if (preg_match('/OmniWeb\/(v*)([^\s|;]+)/i', $agent, $regs)) {
            $browser     = 'OmniWeb';
            $browser_ver = $regs[2];
        }
        if (preg_match('/Netscape([\d]*)\/([^\s]+)/i', $agent, $regs)) {
            $browser     = 'Netscape';
            $browser_ver = $regs[2];
        }
        if (preg_match('/safari\/([^\s]+)/i', $agent, $regs)) {
            $browser     = 'Safari';
            $browser_ver = $regs[1];
        }
        if (preg_match('/MSIE\s([^\s|;]+)/i', $agent, $regs)) {
            $browser     = 'Internet Explorer';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Opera[\s|\/]([^\s]+)/i', $agent, $regs)) {
            $browser     = 'Opera';
            $browser_ver = $regs[1];
        }
        if (preg_match('/NetCaptor\s([^\s|;]+)/i', $agent, $regs)) {
            $browser     = '(Internet Explorer '.$browser_ver.') NetCaptor';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Maxthon/i', $agent, $regs)) {
            $browser     = '(Internet Explorer '.$browser_ver.') Maxthon';
            $browser_ver = '';
        }
        if (preg_match('/360SE/i', $agent, $regs)) {
            $browser     = '(Internet Explorer '.$browser_ver.') 360SE';
            $browser_ver = '';
        }
        if (preg_match('/SE 2.x/i', $agent, $regs)) {
            $browser     = '(Internet Explorer '.$browser_ver.') 搜狗';
            $browser_ver = '';
        }
        if (preg_match('/FireFox\/([^\s]+)/i', $agent, $regs)) {
            $browser     = 'FireFox';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Lynx\/([^\s]+)/i', $agent, $regs)) {
            $browser     = 'Lynx';
            $browser_ver = $regs[1];
        }
        if (preg_match('/Chrome\/([^\s]+)/i', $agent, $regs)) {
            $browser     = 'Chrome';
            $browser_ver = $regs[1];
        }
        if (preg_match('/MicroMessenger\/([^\s]+)/i', $agent, $regs)) {
            $browser     = '微信浏览器';
            $browser_ver = $regs[1];
        }
        if ($browser != '') {
            return ['browser' => $browser, 'browser_ver' => $browser_ver];
        } else {
            return ['browser' => '未知', 'browser_ver' => ''];
        }
    }
}

if ( ! function_exists('get_ip_to_area')) {
    /**
     * 根据IP地址判断地区
     *
     * @param $clientIP
     *
     * @return string
     */
    function get_ip_to_area($clientIP)
    {
        $IpAddress = new IpAddress();
        if ($clientIP == '127.0.0.1') {
            $return = [
                'country'  => '',
                'province' => '',
                'city'     => '',
                'isp'      => '',
            ];

            return $return;
        }
        $address = $IpAddress->ipToAddress($clientIP);
        $return  = [
            'country'  => ! empty($address['country']) ? $address['country'] : '',
            'province' => ! empty($address['province']) ? $address['province'] : '',
            'city'     => ! empty($address['city']) ? $address['city'] : '',
            'isp'      => ! empty($address['isp']) ? $address['isp'] : '',
        ];

        return $return;
    }
}

if ( ! function_exists('list_sort_by')) {
    /**
     * 对查询结果集进行排序
     * @access public
     *
     * @param array  $list   查询结果
     * @param string $field  排序的字段名
     * @param array  $sortby 排序类型
     *                       asc正向排序 desc逆向排序 nat自然排序
     *
     * @return array
     * @author wapai 邮箱:wapai@foxmail.com
     */
    function list_sort_by($list, $field, $sortby = 'asc')
    {
        if (is_array($list)) {
            $refer = $resultSet = array();
            foreach ($list as $i => $data) {
                $refer[$i] = &$data[$field];
            }
            switch ($sortby) {
                case 'asc': // 正向排序
                    asort($refer);
                    break;
                case 'desc':// 逆向排序
                    arsort($refer);
                    break;
                case 'nat': // 自然排序
                    natcasesort($refer);
                    break;
            }
            foreach ($refer as $key => $val) {
                $resultSet[] = &$list[$key];
            }

            return $resultSet;
        }

        return false;
    }
}

if ( ! function_exists('new_addslashes')) {
    /**
     * 返回经addslashes处理过的字符串或数组
     *
     * @param $string 需要处理的字符串或数组
     *
     * @return mixed
     */
    function new_addslashes($string)
    {
        if ( ! is_array($string)) {
            return addslashes($string);
        }
        foreach ($string as $key => $val) {
            $string[$key] = new_addslashes($val);
        }

        return $string;
    }
}

if ( ! function_exists('arr_to_html')) {

    /**
     * 转换数据为HTML代码
     *
     * @param $data 数组
     *
     * @return bool|string
     */
    function arr_to_html($data)
    {
        if (is_array($data)) {
            $str = 'array(';
            foreach ($data as $key => $val) {
                if (is_array($val)) {
                    $str .= "'$key'=>".arr_to_html($val).",";
                } else {
                    //如果是变量的情况
                    if (strpos($val, '$') === 0) {
                        $str .= "'$key'=>$val,";
                    } else {
                        if (preg_match("/^([a-zA-Z_].*)\(/i", $val, $matches)) {
                            //判断是否使用函数
                            if (function_exists($matches[1])) {
                                $str .= "'$key'=>$val,";
                            } else {
                                $str .= "'$key'=>'".new_addslashes($val)."',";
                            }
                        } else {
                            $str .= "'$key'=>'".new_addslashes($val)."',";
                        }
                    }
                }
            }

            return $str.')';
        }

        return false;
    }
}

if ( ! function_exists('new_addslashes')) {
    /**
     * 返回经addslashes处理过的字符串或数组
     *
     * @param $string 需要处理的字符串或数组
     *
     * @return array|string
     */
    function new_addslashes($string)
    {
        if ( ! is_array($string)) {
            return addslashes($string);
        }
        foreach ($string as $key => $val) {
            $string[$key] = new_addslashes($val);
        }

        return $string;
    }
}

if ( ! function_exists('to_guid_string')) {
    /**
     * 根据PHP各种类型变量生成唯一标识号
     *
     * @param mixed $mix 变量
     *
     * @return string
     */
    function to_guid_string($mix)
    {
        if (is_object($mix)) {
            return spl_object_hash($mix);
        } elseif (is_resource($mix)) {
            $mix = get_resource_type($mix).strval($mix);
        } else {
            $mix = serialize($mix);
        }

        return md5($mix);
    }
}

if ( ! function_exists('cmf_array_column')) {
    /**
     * 兼容低版本的array_column
     *
     * @param  $array      多维数组
     * @param  $column_key 需要返回值的列
     * @param  $index_key  可选。作为返回数组的索引/键的列。
     *
     * @return array       返回一个数组，数组的值为输入数组中某个单一列的值。
     */
    function cmf_array_column($array, $column_key, $index_key = null)
    {
        if (function_exists('array_column')) {
            return array_column($array, $column_key, $index_key);
        }

        $result = array();
        foreach ($array as $key => $value) {
            if ( ! is_array($value)) {
                continue;
            }
            if ($column_key) {
                if ( ! isset($value[$column_key])) {
                    continue;
                }
                $tmp = $value[$column_key];
            } else {
                $tmp = $value;
            }
            if ($index_key) {
                $key = isset($value[$index_key]) ? $value[$index_key] : $key;
            }
            $result[$key] = $tmp;
        }

        return $result;
    }
}

if ( ! function_exists('hui_word_time')) {
    /**
     * 传入时间戳,计算距离现在的时间
     *
     * @param number $time 时间戳
     *
     * @return string     返回多少以前
     */
    function hui_word_time($time)
    {
        $time = (int)substr($time, 0, 10);
        $int  = time() - $time;
        $str  = '';
        if ($int <= 2) {
            $str = sprintf('刚刚', $int);
        } elseif ($int < 60) {
            $str = sprintf('%d秒前', $int);
        } elseif ($int < 3600) {
            $str = sprintf('%d分钟前', floor($int / 60));
        } elseif ($int < 86400) {
            $str = sprintf('%d小时前', floor($int / 3600));
        } elseif ($int < 1728000) {
            $str = sprintf('%d天前', floor($int / 86400));
        } else {
            $str = date('Y-m-d H:i:s', $time);
        }

        return $str;
    }
}

if ( ! function_exists('var_export_short')) {
    /**
     * var_export 格式化为5.4数组
     */
    function var_export_short($data, $return = true)
    {
        $dump = var_export($data, true);
        $dump = preg_replace('#(?:\A|\n)([ ]*)array \(#i', '[', $dump); // Starts
        $dump = preg_replace('#\n([ ]*)\),#', "\n$1],", $dump); // Ends
        $dump = preg_replace('#=> \[\n\s+\],\n#', "=> [],\n", $dump); // Empties
        if (gettype($data) == 'object') { // Deal with object states
            $dump = str_replace('__set_state(array(', '__set_state([', $dump);
            $dump = preg_replace('#\)\)$#', "])", $dump);
        } else {
            $dump = preg_replace('#\)$#', "]", $dump);
        }
        if ($return === true) {
            return $dump;
        } else {
            echo $dump;
        }
    }
}

if ( ! function_exists('build_suffix_image')) {
    /**
     * 生成文件后缀图片
     *
     * @param string $suffix 后缀
     * @param null   $background
     *
     * @return string
     */
    function build_suffix_image($suffix, $background = null, $w = '', $h = '')
    {
        $suffix = mb_substr(strtoupper($suffix), 0, 4);
        $total  = unpack('L', hash('adler32', $suffix, true))[1];
        $hue    = $total % 360;
        list($r, $g, $b) = hsv2rgb($hue / 360, 0.3, 0.9);

        $background = $background ? $background : "rgb({$r},{$g},{$b})";
        $w          = $w ? "width:".$w.'px;' : '';
        $h          = $h ? "height:".$h.'px;' : '';

        $icon = <<<EOT
        <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;{$w} {$h}" xml:space="preserve">
            <path style="fill:#E2E5E7;" d="M128,0c-17.6,0-32,14.4-32,32v448c0,17.6,14.4,32,32,32h320c17.6,0,32-14.4,32-32V128L352,0H128z"/>
            <path style="fill:#B0B7BD;" d="M384,128h96L352,0v96C352,113.6,366.4,128,384,128z"/>
            <polygon style="fill:#CAD1D8;" points="480,224 384,128 480,128 "/>
            <path style="fill:{$background};" d="M416,416c0,8.8-7.2,16-16,16H48c-8.8,0-16-7.2-16-16V256c0-8.8,7.2-16,16-16h352c8.8,0,16,7.2,16,16 V416z"/>
            <path style="fill:#CAD1D8;" d="M400,432H96v16h304c8.8,0,16-7.2,16-16v-16C416,424.8,408.8,432,400,432z"/>
            <g><text><tspan x="220" y="380" font-size="124" font-family="Verdana, Helvetica, Arial, sans-serif" fill="white" text-anchor="middle">{$suffix}</tspan></text></g>
        </svg>
EOT;

        return $icon;
    }
}

if ( ! function_exists('hsv2rgb')) {
    /*
    * 将HSV颜色转换为RGB
    */
    function hsv2rgb($h, $s, $v)
    {
        $r = $g = $b = 0;

        $i = floor($h * 6);
        $f = $h * 6 - $i;
        $p = $v * (1 - $s);
        $q = $v * (1 - $f * $s);
        $t = $v * (1 - (1 - $f) * $s);

        switch ($i % 6) {
            case 0:
                $r = $v;
                $g = $t;
                $b = $p;
                break;
            case 1:
                $r = $q;
                $g = $v;
                $b = $p;
                break;
            case 2:
                $r = $p;
                $g = $v;
                $b = $t;
                break;
            case 3:
                $r = $p;
                $g = $q;
                $b = $v;
                break;
            case 4:
                $r = $t;
                $g = $p;
                $b = $v;
                break;
            case 5:
                $r = $v;
                $g = $p;
                $b = $q;
                break;
        }

        return [
            floor($r * 255),
            floor($g * 255),
            floor($b * 255),
        ];
    }
}

if ( ! function_exists('get_templates')) {

    /**
     * 获取前台所有模板名（模板文件夹）
     * @return array
     */
    function get_templates()
    {
        $themePath  = public_path().'template'.DIRECTORY_SEPARATOR;
        $theme_list = get_dir($themePath);

        return $theme_list;
    }
}

if ( ! function_exists('get_template_path')) {

    /**
     * 获取前台模板主题根路径
     *
     * @param string $name 模块
     *
     * @return object|string
     */
    function get_template_path()
    {
        $indexTheme = ! empty(get_config('index_theme')) ? get_config('index_theme') : 'default';
        $themePath  = public_path().'template'.DIRECTORY_SEPARATOR.$indexTheme.DIRECTORY_SEPARATOR;

        return $themePath;
    }
}

if ( ! function_exists('get_tpl_name')) {
    /**
     * 获取对应模板文件
     *
     * @param type string 模板类型，如：list ， 列表模板
     *
     * @return array
     */
    function get_tpl_name()
    {
        $type = input('type', '');
        $path = get_template_path();
        $path = $path.$type.DIRECTORY_SEPARATOR;
        $list = str_replace($path, '', glob($path.'*.html'));

        $arr = [];
        foreach ($list as $key => $value) {
            if ( ! empty($searchValue) && $value != $searchValue) {
                continue;
            }
            $arr[]['name'] = $value;
        }

        return $arr;
    }
}

/**
 * 生成访问插件的url
 *
 * @param string $url    url格式：插件名://控制器名/方法
 * @param array  $vars   参数
 * @param bool   $domain 是否显示域名 或者直接传入域名
 *
 * @return string
 */
function cmf_plugin_url($url, $vars = [], $domain = false)
{
    /*global $CMF_GV_routes;

    if (empty($CMF_GV_routes)) {
        $routeModel    = new \app\common\model\RouteModel();
        $CMF_GV_routes = $routeModel->getRoutes();
    }*/

    $url              = parse_url($url);
    $case_insensitive = true;
    $plugin           = $case_insensitive ? cmf_parse_name($url['scheme']) : $url['scheme'];
    $controller       = $case_insensitive ? cmf_parse_name($url['host']) : $url['host'];
    $action           = trim($case_insensitive ? strtolower($url['path']) : $url['path'], '/');

    /* 解析URL带的参数 */
    if (isset($url['query'])) {
        parse_str($url['query'], $query);
        $vars = array_merge($query, $vars);
    }

    /* 基础参数 */
    $params = [
        '_plugin'     => $plugin,
        '_controller' => $controller,
        '_action'     => $action,
    ];

    $pluginUrl = '\\app\\index\\controller\\PluginController@index?'.http_build_query($params);

    if ( ! empty($vars) && ! empty($CMF_GV_routes[$pluginUrl])) {

        foreach ($CMF_GV_routes[$pluginUrl] as $actionRoute) {
            $sameVars = array_intersect_assoc($vars, $actionRoute['vars']);

            if (count($sameVars) == count($actionRoute['vars'])) {
                ksort($sameVars);
                $pluginUrl = $pluginUrl.'&'.http_build_query($sameVars);
                $vars      = array_diff_assoc($vars, $sameVars);
                break;
            }
        }
    }

    return url($pluginUrl, $vars, true, $domain);
}

/**
 * 添加钩子
 *
 * @param string $hook   钩子名称
 * @param mixed  $params 传入参数
 * @param bool   $once
 *
 * @return mixed
 */
/*function hook($hook, $params = null, $once = false)
{
    $hook = cmf_parse_name($hook, 1);

    return \think\facade\Event::trigger($hook, $params, $once);
}*/

/**
 * 添加钩子,只执行一个
 *
 * @param string $hook   钩子名称
 * @param mixed  $params 传入参数
 *
 * @return mixed
 */
/*function hook_one($hook, $params = null)
{
    $hook = cmf_parse_name($hook, 1);

    return \think\facade\Event::trigger($hook, $params, true);
}*/

/**
 * 获取插件类名
 *
 * @param string $name 插件名
 *
 * @return string
 *
 */
function cmf_get_plugin_class($name, $type = 'hook', $class = null)
{
    $name  = cmf_parse_name($name);
    $class = cmf_parse_name(is_null($class) ? $name : $class, 1);
    switch ($type) {
        case 'controller':
            $namespace = "\\addons\\".$name."\\controller\\".$class;
            break;
        default:
            $namespace = "\\addons\\".$name."\\Plugin";
    }

    return class_exists($namespace) ? $namespace : '';
}

/**
 * 获取插件配置
 *
 * @param string $name 插件名，大驼峰格式
 *
 * @return array
 */
function cmf_get_plugin_config($name)
{
    $class = cmf_get_plugin_class($name);
    if (class_exists($class)) {
        $plugin = new $class();

        return $plugin->getConfig();
    } else {
        return [];
    }
}

//数组排序
if ( ! function_exists('arrayOrder')) {
    function arrayOrder($array, $vkey)
    {
        $newArr = array();
        foreach ($array as $key => $v) {
            $newArr[$key][$vkey] = $v[$vkey];
        }
        array_multisort($newArr, SORT_DESC, $array);//SORT_DESC为降序，SORT_ASC为升序

        return $array;
    }
}

if ( ! function_exists('is_really_writable')) {
// 判断文件或目录是否有写的权限
    function is_really_writable($file)
    {
        if (DIRECTORY_SEPARATOR == '/' and @ ini_get("safe_mode") == false) {
            return is_writable($file);
        }
        if ( ! is_file($file) or ($fp = @fopen($file, "r+")) === false) {
            return false;
        }

        fclose($fp);

        return true;
    }
}

if ( ! function_exists('create_menu')) {
    /**
     * 创建菜单
     *
     * @param array  $menu 菜单数组
     * @param string $app  所属app(插件标识)
     *
     * @return bool
     */
    function create_menu(array $menu, string $app = '')
    {
        try {
            $bl = (new \app\common\model\AuthRule)->createMenu($menu, $app);
        } catch (\Exception $exception) {
            trace("创建菜单失败：".$exception->getMessage(), 'error');
            $bl = false;
        }
        app('cache')->tag('menu')->clear();

        return $bl;
    }
}

if ( ! function_exists('status_menu')) {
    /**
     * 更改状态
     *
     * @param integer $status 状态:normal-正常,hidden-禁用
     * @param string  $app
     */
    function status_menu($status = 1, string $app = '')
    {
        app('cache')->tag('menu')->clear();

        return \app\common\model\AuthRule::where(['app' => $app])->save(['is_menu' => $status]);
    }
}

if ( ! function_exists('del_menu')) {
    /**
     * 删除菜单
     *
     * @param string $app 插件标识
     *
     * @return bool
     */
    function del_menu(string $app)
    {
        app('cache')->tag('menu')->clear();
        $ids = \app\common\model\AuthRule::where(['app' => $app])->column('id');

        return \app\common\model\AuthRule::where(['app' => $app])->delete();
    }
}
if ( ! function_exists('dr_is_empty')) {
    /**
     * 是否为空白
     * @return 是否空白
     */
    function dr_is_empty($value)
    {
        if (is_array($value)) {
            return $value ? 0 : 1;
        }

        return strlen((string)$value) ? 0 : 1;
    }
}

/**
 *  混淆字符串内容
 */
if ( ! function_exists('rndstring')) {
    function rndstring($str)
    {
        if (dr_is_empty($str)) {
            return '';
        }
        //最大间隔距离(如果在检测不到p标记的情况下，加入混淆字串的最大间隔距离)
        $maxpos = 1024;

        //font 的字体颜色
        $fontColor = '#FFFFFF';

        //div span p 标记的随机样式
        $st1                  = chr(mt_rand(ord('A'), ord('Z'))).chr(mt_rand(ord('a'), ord('z'))).chr(mt_rand(ord('a'),
                ord('z'))).mt_rand(100, 999);
        $st2                  = chr(mt_rand(ord('A'), ord('Z'))).chr(mt_rand(ord('a'), ord('z'))).chr(mt_rand(ord('a'),
                ord('z'))).mt_rand(100, 999);
        $st3                  = chr(mt_rand(ord('A'), ord('Z'))).chr(mt_rand(ord('a'), ord('z'))).chr(mt_rand(ord('a'),
                ord('z'))).mt_rand(100, 999);
        $st4                  = chr(mt_rand(ord('A'), ord('Z'))).chr(mt_rand(ord('a'), ord('z'))).chr(mt_rand(ord('a'),
                ord('z'))).mt_rand(100, 999);
        $rndstyle[1]['value'] = '.'.$st1.' { display:none; }';
        $rndstyle[1]['name']  = $st1;
        $rndstyle[2]['value'] = '.'.$st2.' { display:none; }';
        $rndstyle[2]['name']  = $st2;
        $rndstyle[3]['value'] = '.'.$st3.' { display:none; }';
        $rndstyle[3]['name']  = $st3;
        $rndstyle[4]['value'] = '.'.$st4.' { display:none; }';
        $rndstyle[4]['name']  = $st4;
        $mdd                  = mt_rand(1, 4);
        $rndstyleValue        = $rndstyle[$mdd]['value'];
        $rndstyleName         = $rndstyle[$mdd]['name'];
        $reString             = '<style> '.$rndstyleValue.' </style>'.PHP_EOL;

        //附机标记
        $rndem[1] = 'font';
        $rndem[2] = 'div';
        $rndem[3] = 'span';
        $rndem[4] = 'p';

        //读取字符串数据
        $downmix = get_config('downmix');
        if ( ! $downmix) {
            return $str;
        }
        $downmix = explode(PHP_EOL, (string)$downmix);
        if ( ! $downmix) {
            return $str;
        }
        $totalitem = 0;
        foreach ($downmix as $v) {
            if (trim($v)) {
                $totalitem++;
                $rndstring[$totalitem] = trim($v);
            }
        }

        //处理要防采集的字段
        $strlen = strlen((string)$str) - 1;
        $prepos = 0;
        for ($i = 0; $i <= $strlen; $i++) {
            if ($i + 2 >= $strlen || $i < 50) {
                $reString .= $str[$i];
            } else {
                $ntag = @strtolower($str[$i].$str[$i + 1].$str[$i + 2]);
                if ($ntag == '</p' || ($ntag == '<br' && $i - $prepos > $maxpos)) {
                    $dd     = mt_rand(1, 4);
                    $emname = $rndem[$dd];
                    $dd     = mt_rand(1, $totalitem);
                    $rnstr  = $rndstring[$dd];
                    if ($emname != 'font') {
                        $rnstr = ' <'.$emname.' class="'.$rndstyleName.'">'.$rnstr.'</'.$emname.'> ';
                    } else {
                        $rnstr = ' <font color="'.$fontColor.'" style="display:none;">'.$rnstr.'</font> ';
                    }
                    $reString .= $rnstr.$str[$i];
                    $prepos   = $i;
                } else {
                    $reString .= $str[$i];
                }
            }
        }

        return $reString;
    }
}

if ( ! function_exists('tag_url')) {
    /**
     * 生成Tag URL
     *
     * @param $tid
     * @param $domain
     *
     * @return string
     */
    function tag_url($tid, $domain = null)
    {
        if ($domain) {
            $domain = rtrim($domain, '/');

            return $domain.url('/index/search/tag', array('id' => $tid), false);
        }

        return url('/index/search/tag', array('id' => $tid), $domain);
    }
}

if ( ! function_exists('get_random_str')) {
    /**
     * 产生一个指定长度的随机字符串,并返回给用户
     *
     * @param integer $len 产生字符串的长度
     *
     * @return string 随机字符串
     */
    function get_random_str($len = 6)
    {
        $chars    = array(
            "a",
            "b",
            "c",
            "d",
            "e",
            "f",
            "g",
            "h",
            "i",
            "j",
            "k",
            "l",
            "m",
            "n",
            "o",
            "p",
            "q",
            "r",
            "s",
            "t",
            "u",
            "v",
            "w",
            "x",
            "y",
            "z",
            "A",
            "B",
            "C",
            "D",
            "E",
            "F",
            "G",
            "H",
            "I",
            "J",
            "K",
            "L",
            "M",
            "N",
            "O",
            "P",
            "Q",
            "R",
            "S",
            "T",
            "U",
            "V",
            "W",
            "X",
            "Y",
            "Z",
            "0",
            "1",
            "2",
            "3",
            "4",
            "5",
            "6",
            "7",
            "8",
            "9"
        );
        $charsLen = count($chars) - 1;
        // 将数组打乱
        shuffle($chars);
        $output = "";
        for ($i = 0; $i < $len; $i++) {
            $output .= $chars[mt_rand(0, $charsLen)];
        }

        return $output;
    }
}

if ( ! function_exists('get_category_sub')) {
    /**
     * 获取栏目所有下级ID
     *
     * @param int   $cateId  栏目ID
     * @param bool  $is_self true-包含自己，false-不含自己
     * @param array $extend  扩展其他字段以限制查询条件
     *
     * @return array
     */
    function get_category_sub($cateId, $is_self = false, $extend = [])
    {
        $all     = \app\common\model\Category::where(['pid' => $cateId])->where($extend)->column('id');
        $tempArr = $all;
        if ($is_self) {
            $tempArr[] = $cateId;
        }
        foreach ($all as $key => $value) {
            if ($temp = get_category_sub($value)) {
                $tempArr = array_merge($tempArr, $temp);
            }
        }

        return $tempArr;
    }
}

if ( ! function_exists('index_url')) {
    /**
     * 在其他模块生成前台URL
     *
     * @param             $url       string URL地址，伪静态URL，没有则默认跟TP url生成一样
     * @param array       $param     参数
     * @param bool|string $suffix
     * @param bool|string $domain
     * @param string      $baseFile  增加入口文件
     * @param array       $ruleParam 规则变量，补充额外的规则变量
     * @param array       $extend    在伪静态情况下，该参数追加到url地址上
     *
     * @return string|string[]
     */
    function index_url(
        $url,
        $param = [],
        $suffix = true,
        $domain = false,
        $baseFile = '',
        $ruleParam = [],
        $extend = []
    ) {
        $site = get_config(); // 获取伪静态规则
        if ($site['url_mode'] == 1 && ! empty($site['url_rewrite'])) {
            $cacheId   = to_guid_string(array_merge([$site['url_rewrite'], $url, ['domain' => $domain]], $param));
            $cache_url = cache($cacheId);
            if ( ! app()->isDebug() && $cache_url) {
                return $cache_url;
            }

            // 提取设置好的伪静态变量
            $urlRewrite          = [];
            $site['url_rewrite'] = json_decode($site['url_rewrite'], true);
            foreach ($site['url_rewrite'] as $key => $value) {
                $value = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $value);
                if (preg_match_all('/<\w+\??>/', $value, $matches)) {
                    foreach ($matches[0] as $name) {
                        if (strpos($name, '?')) {
                            $name = substr($name, 1, -2);
                        } else {
                            $name = substr($name, 1, -1);
                        }
                        $urlRewrite[$name] = $name;
                    }
                }
            }

            // cms默认变量
            $rules = [];
            $cor   = array_merge($urlRewrite, [
                'catdir'  => 'pid', // 栏目父级英文
                'catname' => 'dirname',
                'catid'   => 'id',
                'id'      => 'aid', // 文章ID
                'model'   => 'model_id',
                'year'    => 'update_time',
                'month'   => 'update_time',
                'day'     => 'update_time',
                'page'    => 'page'
            ], $ruleParam);

            if (isset($param['update_time'])) {
                $param['update_time'] = strtotime($param['update_time']) ?: $param['update_time'];
            }
            foreach ($cor as $key => $value) {
                if ( ! isset($param[$value])) {
                    continue;
                }
                if ($key == 'year') {
                    $rules[$key] = date('Y', $param[$value]);
                    continue;
                }
                if ($key == 'month') {
                    $rules[$key] = date('m', $param[$value]);
                    continue;
                }
                if ($key == 'day') {
                    $rules[$key] = date('d', $param[$value]);
                    continue;
                }
                $rules[$key] = $param[$value];
            }

            // 扩展参数赋值
            foreach ($extend as $key => $value) {
                $extend[$key] = isset($param[$key]) ? $param[$key] : $value;
            }

            $rule    = $rules;
            $oldUrl  = $url; // 不匹配时，给到动态
            $url     = ltrim($url, '/');
            $rewrite = $site['url_rewrite'][$url] ?? '';
            if ($rewrite && $rewriteArr = explode(',', $rewrite)) {

                // 匹配其中一条规则
                foreach ($rewriteArr as $value) {
                    $value = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $value);

                    // 提取路由规则中的变量
                    $allTmp = [];
                    $fTmp   = [];
                    if (preg_match_all('/<\w+\??>/', $value, $matches)) {
                        foreach ($matches[0] as $name) {
                            if (strpos($name, '?')) {
                                $name = substr($name, 1, -2);
                            } else {
                                $name = substr($name, 1, -1);
                            }
                            if (isset($rule[$name])) {
                                $fTmp[] = $name;
                            }
                            $allTmp[] = $name;
                        }
                    }
                    if (count($allTmp) == count($fTmp)) {
                        $rewrite = $value;
                    }
                }

                $rewrite = stripslashes($rewrite); // 删除反斜杠

                // 分页页码存在的情况下必须带上
                if (isset($rule['page']) && is_numeric($rule['page']) && empty($extend['page'])) {
                    $extend['page'] = $rule['page'];
                }

                array_walk($rule, function ($val, $key) use (&$rewrite, &$extend, $param) {
                    if ((strpos($rewrite, '<catdir>') !== false || strpos($rewrite,
                                '<catdir?>') !== false) && $key == 'catdir' && isset($param['pid'])) {
                        $name = '';
                        if ($param['pid']) {
                            $name = \think\facade\Db::name('category')->where(['id' => $param['pid']])->where(['model_id' => $param['model_id']])->value('dirname');
                        }
                        if ((strpos($rewrite, '<catname>') !== false || strpos($rewrite, '<catname?>') !== false)) {
                            $val = $name;
                        } else {
                            $val = $name ? $name : $param['dirname']; // 父级不存在使用当前目录
                        }
                    } else {
                        if ((strpos($rewrite, '<model>') !== false || strpos($rewrite,
                                    '<model?>') !== false) && $key == 'model') {
                            $modelInfo = \app\admin\model\cms\Model::where(['id' => $param['model_id']])->cache()->find();
                            if ($modelInfo) {
                                $val = $modelInfo && $modelInfo->diyname ? $modelInfo->diyname : $modelInfo->tablename;
                            }
                        }
                    }

                    // url文章别名
                    if ((strpos($rewrite, '<id>') !== false || strpos($rewrite,
                                '<id?>') !== false) && $key == 'id' && ! empty($param['diyname'])) {
                        $val = $param['diyname'];
                    }

                    if (strpos($rewrite, '<'.$key.'>') !== false || strpos($rewrite, '<'.$key.'?>') !== false) {
                        unset($extend[$key]); // 对已匹配的参数，剔除扩展参数
                    }

                    $rewrite = str_replace(["<{$key}>", "<{$key}?>"], $val, $rewrite);
                });
                $rewrite = str_replace(['$', '//'], ['', '/'], $rewrite);
                $url     = (string)url($rewrite, $extend, false, $domain);
                $url     = preg_replace("/\/([\w]+)\.php\//i", "/", $url);
                if ( ! app()->isDebug()) {
                    cache($cacheId, $url);
                }

                return $url;
            } else {
                $url  = \think\facade\Route::buildUrl($oldUrl, $param)->suffix($suffix)->domain($domain)->build();
                $file = $baseFile ?: app('request')->baseFile();
                $url  = str_replace($file, '', $url);
                if ( ! app()->isDebug()) {
                    cache($cacheId, $url);
                }

                return $url;
            }
        } else {
            // 生成URL地址
            $url = \think\facade\Route::buildUrl($url, $param)->suffix($suffix)->domain($domain)->build();
            // 是否显示入口文件index.php文件
            $siteFile = get_config('url_mode') == 0 ? get_config('url_file') : 0;
            if ($siteFile == 1) { // 显示入口文件，用于兼容不支持伪静态
                $file = $baseFile ? $baseFile : '/index.php'; // 默认index_url 跳转的是首页

                if ($domain) {
                    if (preg_match("/^(https|http):\/\/([^\/]+)/i", $url, $mat)) {
                        $url = preg_replace("/^(https|http):\/\/([^\/]+)/i", '', $url);
                        $url = $mat[0].$file.preg_replace("/\/([\w]+)\.php\//i", "/", $url);
                    }
                } else {
                    $url = $file.preg_replace("/\/([\w]+)\.php\//i", "/", $url);
                }
            } else { // 隐藏入口文件，必须配置URL重写
                $url = $baseFile ? preg_replace("/\/([\w]+)\.php\//i", "/$baseFile/",
                    $url) : preg_replace("/\/([\w]+)\.php\//i", "/", $url);
            }

            return $url;
        }
    }
}
if ( ! function_exists('controller')) {
    /**
     * 获取模型管理操作的控制类
     *
     * @param array | integer $info 模型ID、或栏目ID、查询出的模型数组、栏目数组
     * @param Closure         $fun  回调
     * @param string          $type model-模型数据，category-栏目数据
     *
     * @return mixed
     */
    function controller($info, Closure $fun, $type = 'model')
    {
        $category = [];
        if (is_numeric($info) && $type == 'category') {
            $category = get_category($info);
            $info     = $category['model_id'];
        } else {
            if (is_array($info) && $type == 'category') {
                $category = $info;
                $info     = $info['model_id'];
            } else {
                if (is_array($info) && $type == 'model') {
                    $info = $info['id'];
                }
            }
        }

        $model = \app\common\model\Models::where(['id' => $info, 'status' => 1])->find();
        $c     = '\app\common\model\Content';
        $obj   = (new $c);

        return $fun($obj, $model, $category);
    }
}
